package com.zorzhi.automation.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.zorzhi.automation.entity.MergeEntity;
import com.zorzhi.automation.entity.R;
import com.zorzhi.automation.service.MergeService;
import com.zorzhi.automation.utils.MergeUtil;
import java.nio.file.Paths;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;


@Slf4j
@RestController
@RequestMapping("/api")
public class GitController {

    @Resource
    private MergeService mergeService;

    /**
     * 获取git仓库的分支
     */
    @PostMapping("/getBranches")
    public R getBranches(@RequestBody MergeEntity mergeEntity) {
        R mergeFileContent = MergeUtil.getMergeFileContent();
        if (mergeFileContent.getCode() != 200) {
            return mergeFileContent;
        }
        MergeEntity mergeEntityTxt = (MergeEntity) mergeFileContent.getData();
        BeanUtil.copyProperties(mergeEntityTxt, mergeEntity);

        String gitUrl = mergeEntity.getGitUrl();
        String account = mergeEntity.getGitAccount();
        String password = mergeEntity.getGitPassword();
        if (StrUtil.isEmpty(password)) {
            password = System.getenv("Git_P");
            if (StrUtil.isEmpty(password)) {
                password = MergeUtil.getMergeFilePassword();
            }
            mergeEntity.setGitPassword(password);
        }
        // 校验参数
        if (gitUrl == null || account == null || password == null) {
            return R.failure("缺少必要参数");
        }

        return mergeService.getBranches(mergeEntity);
    }

    /**
     * 自动合并分支(页面操作)
     */
    @PostMapping("/auto/merge")
    public R autoMerge(@RequestBody MergeEntity mergeEntity) {
        R mergeFileContent = MergeUtil.getMergeFileContent();
        if (mergeFileContent.getCode() != 200) {
            return mergeFileContent;
        }

        MergeEntity mergeEntityTxt = (MergeEntity) mergeFileContent.getData();

        BeanUtil.copyProperties(mergeEntityTxt, mergeEntity, "branchName", "operate");
        return merge(mergeEntity);
    }


    /**
     * 自动合并分支(命令行或直接接口)
     */
    @GetMapping("/auto/merge2")
    public R autoMerge2(@RequestParam("branchName") String branchName, @RequestParam("operate") String operate) {

        R mergeFileContent = MergeUtil.getMergeFileContent();
        if (mergeFileContent.getCode() != 200) {
            return mergeFileContent;
        }
        MergeEntity mergeEntity = (MergeEntity) mergeFileContent.getData();
        mergeEntity.setBranchName(branchName);
        mergeEntity.setOperate(operate);

        String password = mergeEntity.getGitPassword();
        if (StrUtil.isEmpty(password)) {
            password = System.getenv("Git_P");
            mergeEntity.setGitPassword(password);
        }

        return merge(mergeEntity);
    }

    /**
     * 公共合并方法
     *
     * @param mergeEntity
     * @return
     */
    private R merge(MergeEntity mergeEntity) {
        String gitUrl = mergeEntity.getGitUrl();
        String account = mergeEntity.getGitAccount();
        String password = mergeEntity.getGitPassword();
        String branchName = mergeEntity.getBranchName();
        String deploymentPath = mergeEntity.getDeploymentPath();
        String projectPath = mergeEntity.getProjectPath();
        String pcProjectName = mergeEntity.getPcProjectName();
        String vueProjectName = mergeEntity.getVueProjectName();
        String uniAppProjectName = mergeEntity.getUniAppProjectName();
        String operate = mergeEntity.getOperate();  // 操作类型（1或空：合并且打包，2：只合并，3：只打包）

        if (StrUtil.isEmpty(password)) {
            password = System.getenv("Git_P");
            if (StrUtil.isEmpty(password)) {
                password = MergeUtil.getMergeFilePassword();
            }
            mergeEntity.setGitPassword(password);
        }

        // 校验参数
        if (StrUtil.isEmpty(gitUrl) || StrUtil.isEmpty(account) || StrUtil.isEmpty(password)
                || StrUtil.isEmpty(branchName) || StrUtil.isEmpty(deploymentPath) || StrUtil.isEmpty(projectPath)) {
            return R.failure("缺少必要参数");
        }

        // 不是只打包情况下，pcProjectName 不能为空，因为要获取sql文件
        if (!"3".equals(operate) && StrUtil.isEmpty(pcProjectName)) {
            return R.failure("操作类型为 合并且打包或只合并时，PC项目名称 不能为空");
        }

        // TODO 合并、打包
        String outputPath = null;

        Map<String, String> resultMap = new HashMap<>();
        // 1或空：合并且打包
        if ("1".equals(operate) || "".equals(operate)) {
            // 1、主干代码 合并 到 分支上
            R merge = mergeService.merge(mergeEntity);
            if (merge.getCode() != 200) {
                System.err.println(merge.getMsg());
                return merge;
            }
            resultMap = (Map<String, String>) merge.getData();
            outputPath = resultMap.get("path");

            // 2、进行打包
            R packageResult = packageCall(projectPath, outputPath, pcProjectName, vueProjectName, uniAppProjectName);
            if (packageResult.getCode() != 200) {
                return packageResult;
            }

        } else if ("2".equals(operate)) { // 只合并
            R merge = mergeService.merge(mergeEntity);
            if (merge.getCode() != 200) {
                System.err.println(merge.getMsg());
                return merge;
            }
            resultMap = (Map<String, String>) merge.getData();
            outputPath = resultMap.get("path");

        } else if ("3".equals(operate)) { // 只打包
            // 1、切换 到 分支上
            R switchBranch = mergeService.switchBranch(mergeEntity);
            if (switchBranch.getCode() != 200) {
                System.err.println(switchBranch.getMsg());
                return switchBranch;
            }

            // 2、创建分支下日期文件夹
            outputPath = MergeUtil.createBranchDirectory(deploymentPath, branchName);

            // 3、进行打包
            R packageResult = packageCall(projectPath, outputPath, pcProjectName, vueProjectName, uniAppProjectName);
            if (packageResult.getCode() != 200) {
                return packageResult;
            }
        }

        System.err.println("部署包输出路径：" + outputPath);


        // TODO 处理后再切换回 主干
        mergeEntity.setBranchName("master");
        R switchBranch = mergeService.switchBranch(mergeEntity);
        if (switchBranch.getCode() != 200) {
            System.err.println(switchBranch.getMsg());
            return switchBranch;
        }
        System.err.println(switchBranch.getMsg());


        // TODO 根据分支最后提交日期，获取sql文件
        String latestCommitDate = resultMap.get("latestCommitDate");
        if (StrUtil.isNotBlank(latestCommitDate)) {
            try {
                File sqlTargetFile = new File(outputPath, "sql");
                if (!sqlTargetFile.exists()) {
                    sqlTargetFile.mkdirs();
                }
                String sqlSourcePath = Paths.get(projectPath, pcProjectName, "src", "main", "java", "sql", "update").toString();
                MergeUtil.findAndCopySqlFiles(latestCommitDate, sqlSourcePath, sqlTargetFile.getPath());
            } catch (Exception e) {
                e.printStackTrace();
                return R.failure("根据分支最后一次提交日期拉取SQL文件异常：" + e.getMessage());
            }
        }


        // TODO 将部署包 进行压缩
        if ("1".equals(operate) || "3".equals(operate)) {
            try {
                // 压缩指定目录下 "api", "dist", "web" 文件到 一个压缩包
                boolean result = MergeUtil.compressFolders(outputPath);
                if (result) {
                    // 删除 "api", "dist", "web" 文件夹
                    String[] deleteDir = new String[]{"api", "dist", "web"};
                    for (String dir : deleteDir) {
                        MergeUtil.deleteDirectory(new File(outputPath, dir));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                return R.failure("压缩部署包异常：" + e.getMessage());
            }
        }

        return R.success("操作成功，文件已存放到以下目录\n【" + outputPath + "】");
    }


    private R packageCall(String projectPath, String outputPath, String pcProjectName, String vueProjectName, String uniAppProjectName) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 存储各任务的结果
        List<Future<R>> futures = new ArrayList<>();
        
        // 2、maven进行打包
        if (StrUtil.isNotBlank(pcProjectName)) {
            // 兼容不同的系统
            String jarProjectPath = Paths.get(projectPath, pcProjectName).toString();
            Future<R> mavenFuture = executor.submit(() -> mergeService.mavenPackage(jarProjectPath, outputPath));
            futures.add(mavenFuture);
        }

        // 3、vue 项目 打包
        if (StrUtil.isNotBlank(vueProjectName)) {
            String vueProjectPath = Paths.get(projectPath, vueProjectName).toString();
            Future<R> vueFuture = executor.submit(() -> mergeService.vuePackage(vueProjectPath, outputPath));
            futures.add(vueFuture);
        }

        // 4、uniapp 项目 打包
        if (StrUtil.isNotBlank(uniAppProjectName)) {
            String uniAppProjectPath = Paths.get(projectPath, uniAppProjectName).toString();
            Future<R> uniAppFuture = executor.submit(() -> mergeService.uniAppPackage(uniAppProjectPath, outputPath));
            futures.add(uniAppFuture);
        }
        
        // 关闭线程池，不再接受新任务
        executor.shutdown();
        
        // 收集所有结果并检查是否有错误
        for (Future<R> future : futures) {
            try {
                R packageResult = future.get();
                if (packageResult.getCode() == 500) {
                    System.err.println(packageResult.getMsg());
                    // 等待所有任务完成后再返回
                    executor.shutdownNow();
                    return packageResult;
                }
            } catch (InterruptedException | ExecutionException e) {
                System.err.println("执行打包任务时发生异常：" + e.getMessage());
                executor.shutdownNow();
                return R.failure("执行打包任务时发生异常：" + e.getMessage());
            }
        }
        
        // 等待所有任务完成
        try {
            if (!executor.awaitTermination(1, TimeUnit.HOURS)) {
                executor.shutdownNow();
                return R.failure("打包任务超时");
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            return R.failure("打包任务被中断：" + e.getMessage());
        }
        
        System.out.println("-----------------打包完成------------------");
        return R.success("打包成功");
    }
}